Random Forests - Predicting Daily Cryptocurrencies Returns¶

Table of Contents¶

  • 1. Loading Data

    • 1.1. Connect to sql server
    • 1.2. Load assets (coins) historical daily returns
    • 1.3. Loading factor portfolios daily returns
    • 1.4. Loading historical daily risk free rate
    • 1.5. Alligning data
    • 1.6. Splitting data
  • 2. In-Sample analysis

    • 2.1. Run random forest regression
    • 2.2. Average results for all coins
    • 2.3. Results for Ethereum
  • 3. Out-of-Sample analysis

    • 3.1. Average results for all coins
    • 3.2. Results for Ethereum
  • 4. Out-of-Sample analysis (rolling)

    • 4.1. Average results for all coins
    • 4.2. Results for Ethereum
  • 5. Out-of-Sample analysis (rolling - all windows)

    • 5.1. Average results for all coins
    • 5.2. Results for Ethereum
  • 6. Comparing the results

    • 6.1. Across all coins
      • 6.1.1 In-sample
      • 6.1.2 Out-of-sample (static)
      • 6.1.3 Out-of-sample (rolling - 1Y window)
      • 6.1.4 Out-of-sample (rolling - all windows)
    • 6.2. for Ethereum
      • 6.2.1 In-sample
      • 6.2.2 Out-of-sample (static)
      • 6.2.3 Out-of-sample (rolling - 1Y window)
      • 6.2.4 Out-of-sample (rolling - all windows)
In [ ]:
%matplotlib inline
%load_ext autoreload
%autoreload 2

from datetime import timedelta
from time import time
import warnings
warnings.filterwarnings('ignore')

import numpy as np
import pandas as pd
import pandas_datareader.data as web

import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.ensemble import RandomForestRegressor
import scipy.stats as stats


from util import SqlServerConnector

sns.set_style('whitegrid')

1. Loading Data¶

1.1. Connect to sql server¶

In [ ]:
conn = SqlServerConnector(server_name='', 
                                     database_name='', 
                                     user_name='', 
                                     password='')

1.2. Load assets (coins) historical daily returns¶

In [ ]:
assets_historical_returns = conn.get_rets(daily=True, portfolios=False, start='2010-01-01', end='2023-12-31')
assets_historical_returns.columns = assets_historical_returns.columns.str.strip()
assets_historical_returns

1.3. Loading factor portfolios daily returns¶

In [ ]:
factors_historical_returns = conn.get_factors(daily=True).shift().dropna()
factors_historical_returns

1.4. Loading historical daily risk free rate¶

In [ ]:
rf = web.DataReader('F-F_Research_Data_5_Factors_2x3', 'famafrench', start='2010', end='2022')[0]
rf.index = rf.index.to_timestamp()
rf = rf.RF.reindex(pd.date_range(start='2010', end='2023', freq='d')).ffill()/30
rf

1.5. Alligning data¶

In [ ]:
rf = rf.loc[factors_historical_returns.index]
assets_historical_returns = assets_historical_returns.loc[factors_historical_returns.index]

# Subtract risk free rate from assets returns to find asset exess returns
# assets_historical_returns = assets_historical_returns.sub(rf, axis=0)

1.6. Splitting data¶

In [ ]:
in_sample_pct = 0.8

## Assets
assets_historical_returns_in_sample = assets_historical_returns.iloc[:int(in_sample_pct*len(assets_historical_returns))]
assets_historical_returns_out_of_sample = assets_historical_returns.iloc[int(in_sample_pct*len(assets_historical_returns)):]

## Factors
factors_historical_returns_in_sample = factors_historical_returns.iloc[:int(in_sample_pct*len(factors_historical_returns))]
factors_historical_returns_out_of_sample = factors_historical_returns.iloc[int(in_sample_pct*len(factors_historical_returns)):]

2. In-Sample analysis¶

2.1. Run random forest regression¶

In [ ]:
mod = RandomForestRegressor(n_estimators=100)
res = mod.fit(factors_historical_returns_in_sample, assets_historical_returns_in_sample)
predicted_returns_in_sample = pd.DataFrame(res.predict(factors_historical_returns_in_sample), 
                                 index=assets_historical_returns_in_sample.index,
                                 columns=assets_historical_returns_in_sample.columns
                                )
predicted_returns_in_sample

2.2. Average results for all coins¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01
significance_level = 0.1

results=[]
for stop_loss_factor in stop_loss_factors:
    t_stats = []
    p_values = []
    win_rates = []
    avg_daily_rets = []
    cols=[]
    for coin in assets_historical_returns_in_sample.columns:
        predicted_returns = predicted_returns_in_sample[coin]

        ground_truth = (assets_historical_returns_in_sample.loc[:, coin]>=0).astype(int).replace(0,-1)
        predictions = (predicted_returns>=0).astype(int).replace(0,-1)
        signals = predictions - ground_truth
        win_rate = (signals==0).sum()/len(signals)

        strategy_returns_coin = (assets_historical_returns_in_sample.loc[:,coin] * predictions).fillna(0)
        strategy_returns_coin.loc[strategy_returns_coin>=0] = strategy_returns_coin.loc[strategy_returns_coin>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
        strategy_returns_coin.loc[strategy_returns_coin<0] = strategy_returns_coin.loc[strategy_returns_coin<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

        # Perform the one-sample t-test
        t_test = stats.ttest_1samp(a=strategy_returns_coin, popmean=0, alternative='greater')

        win_rates.append(win_rate)
        t_stats.append(t_test.statistic)
        p_values.append(t_test.pvalue)
        avg_daily_rets.append(strategy_returns_coin.mean())
        cols.append(coin)

    first_results = pd.DataFrame({'win_rate':win_rates, 't_stats':t_stats, 'p_value':p_values, 'avg_daily_returns':avg_daily_rets}, index=cols)
    results.append(first_results.mean().values)
average_results_all_coins_in_sample = pd.DataFrame(results, index=stop_loss_factors, columns=first_results.columns)
average_results_all_coins_in_sample

2.3. Results for Ethereum¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01
significance_level = 0.1

coin_results_in_sample = pd.DataFrame()
rets = pd.DataFrame()
coin = 'ethereum'
for stop_loss_factor in stop_loss_factors:
    predicted_returns = predicted_returns_in_sample[coin]

    ground_truth = (assets_historical_returns_in_sample.loc[:, coin]>=0).astype(int).replace(0,-1)
    predictions = (predicted_returns>=0).astype(int).replace(0,-1)
    signals = predictions - ground_truth
    win_rate = (signals==0).sum()/len(signals)

    strategy_returns = (assets_historical_returns_in_sample.loc[:,coin] * predictions).fillna(0)
    strategy_returns.loc[strategy_returns>=0] = strategy_returns.loc[strategy_returns>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
    strategy_returns.loc[strategy_returns<0] = strategy_returns.loc[strategy_returns<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

    # Perform the one-sample t-test
    t_test = stats.ttest_1samp(a=strategy_returns, popmean=0, alternative='greater')
    
    t_stat = t_test.statistic
    p_value = t_test.pvalue
    avg_daily_rets = strategy_returns.mean()
    
    first_results = pd.DataFrame({'win_rate':win_rate, 't_stats':t_stat, 'p_value':p_value, 'avg_daily_return':avg_daily_rets}, index=[stop_loss_factor])
    
    coin_results_in_sample = pd.concat([coin_results_in_sample, first_results])
    rets = pd.concat([rets, strategy_returns.to_frame()], axis=1)
rets.columns = stop_loss_factors
coin_results_in_sample
In [ ]:
strategy_compounded_returns = rets.cumsum().apply(np.exp)
btc_bh = assets_historical_returns_in_sample.bitcoin.cumsum().apply(np.exp)
btc_bh = btc_bh.append(pd.Series([1], index=[rets.index.min()-timedelta(days=1)])).sort_index()
btc_bh.name = 'Bitcoin'
portfolios_compared = pd.concat([strategy_compounded_returns,btc_bh], axis=1).fillna(1)
portfolios_compared.plot(figsize=(20,12), legend=True, logy=True)

3. Out-Of-Sample analysis¶

In [ ]:
predicted_returns_out_of_sample = pd.DataFrame(res.predict(factors_historical_returns_out_of_sample), 
                                         index=assets_historical_returns_out_of_sample.index,
                                         columns=assets_historical_returns_out_of_sample.columns
                                        )

3.1. Average results for all coins¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01
significance_level = 0.1

results=[]
for stop_loss_factor in stop_loss_factors:
    t_stats = []
    p_values = []
    win_rates = []
    avg_daily_rets = []
    cols=[]
    for coin in assets_historical_returns_out_of_sample.columns:
        predicted_returns = predicted_returns_out_of_sample[coin]

        ground_truth = (assets_historical_returns_out_of_sample.loc[:, coin]>=0).astype(int).replace(0,-1)
        predictions = (predicted_returns>=0).astype(int).replace(0,-1)
        signals = predictions - ground_truth
        win_rate = (signals==0).sum()/len(signals)

        strategy_returns_coin = (assets_historical_returns_out_of_sample.loc[:,coin] * predictions).fillna(0)
        strategy_returns_coin.loc[strategy_returns_coin>=0] = strategy_returns_coin.loc[strategy_returns_coin>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
        strategy_returns_coin.loc[strategy_returns_coin<0] = strategy_returns_coin.loc[strategy_returns_coin<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

        # Perform the one-sample t-test
        t_test = stats.ttest_1samp(a=strategy_returns_coin, popmean=0, alternative='greater')

        win_rates.append(win_rate)
        t_stats.append(t_test.statistic)
        p_values.append(t_test.pvalue)
        avg_daily_rets.append(strategy_returns_coin.mean())
        cols.append(coin)

    first_results = pd.DataFrame({'win_rate':win_rates, 't_stats':t_stats, 'p_value':p_values, 'avg_daily_returns':avg_daily_rets}, index=cols)
    results.append(first_results.mean().values)
average_results_all_coins_out_of_sample = pd.DataFrame(results, index=stop_loss_factors, columns=first_results.columns)
average_results_all_coins_out_of_sample

3.2. Results for ethereum¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01
significance_level = 0.1

coin_results_out_of_sample = pd.DataFrame()
rets = pd.DataFrame()
coin = 'ethereum'
for stop_loss_factor in stop_loss_factors:
    predicted_returns = predicted_returns_out_of_sample[coin]

    ground_truth = (assets_historical_returns_out_of_sample.loc[:, coin]>=0).astype(int).replace(0,-1)
    predictions = (predicted_returns>=0).astype(int).replace(0,-1)
    signals = predictions - ground_truth
    win_rate = (signals==0).sum()/len(signals)

    strategy_returns = (assets_historical_returns_out_of_sample.loc[:,coin] * predictions).fillna(0)
    strategy_returns.loc[strategy_returns>=0] = strategy_returns.loc[strategy_returns>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
    strategy_returns.loc[strategy_returns<0] = strategy_returns.loc[strategy_returns<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

    # Perform the one-sample t-test
    t_test = stats.ttest_1samp(a=strategy_returns, popmean=0, alternative='greater')
    
    t_stat = t_test.statistic
    p_value = t_test.pvalue
    avg_daily_rets = strategy_returns.mean()
    
    first_results = pd.DataFrame({'win_rate':win_rate, 't_stats':t_stat, 'p_value':p_value, 'avg_daily_return':avg_daily_rets}, index=[stop_loss_factor])
    
    coin_results_out_of_sample = pd.concat([coin_results_out_of_sample, first_results])
    rets = pd.concat([rets, strategy_returns.to_frame()], axis=1)
rets.columns = stop_loss_factors
coin_results_out_of_sample
In [ ]:
strategy_compounded_returns = rets.cumsum().apply(np.exp)
btc_bh = assets_historical_returns_out_of_sample.bitcoin.cumsum().apply(np.exp)
btc_bh = btc_bh.append(pd.Series([1], index=[rets.index.min()-timedelta(days=1)])).sort_index()
btc_bh.name = 'Bitcoin'
portfolios_compared = pd.concat([strategy_compounded_returns,btc_bh], axis=1).fillna(1)
portfolios_compared.plot(figsize=(20,12), legend=True, logy=True)

4. Out-Of-Sample analysis (rolling)¶

In [ ]:
window = 365
conn2 = SqlServerConnector(server_name='DESKTOP-O0P86FB', 
                         database_name='CryplogModels', 
                         user_name='AbdullahBahi', 
                         password='277776')

4.1. Average results for all coins¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01

results=[]
for stop_loss_factor in stop_loss_factors:
    t_stats = []
    p_values = []
    win_rates = []
    avg_daily_rets = []
    for coin in assets_historical_returns_out_of_sample.columns:
        predicted_returns = conn2.sql_to_df(f'select * from RF_3Factor where asset = \'{coin}\' and window = {window} order by date')
        predicted_returns['Date'] = pd.to_datetime(predicted_returns.Date)
        predicted_returns.set_index(['Date'], inplace=True)
        predicted_returns = predicted_returns.predicted_return
        ground_truth = (assets_historical_returns.loc[predicted_returns.index, coin]>=0).astype(int).replace(0,-1)
        predictions = (predicted_returns>=0).astype(int).replace(0,-1)
        signals = predictions - ground_truth
        win_rate = (signals==0).sum()/len(signals)

        strategy_returns_coin = (assets_historical_returns.loc[predicted_returns.index,coin] * predictions).fillna(0)
        strategy_returns_coin.loc[strategy_returns_coin>=0] = strategy_returns_coin.loc[strategy_returns_coin>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
        strategy_returns_coin.loc[strategy_returns_coin<0] = strategy_returns_coin.loc[strategy_returns_coin<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

        # Perform the one-sample t-test
        t_test = stats.ttest_1samp(a=strategy_returns_coin, popmean=0, alternative='greater')

        win_rates.append(win_rate)
        t_stats.append(t_test.statistic)
        p_values.append(t_test.pvalue)
        avg_daily_rets.append(strategy_returns_coin.mean())

    first_results = pd.DataFrame({'win_rate':win_rates, 't_stats':t_stats, 'p_value':p_values, 'avg_daily_returns':avg_daily_rets}, index=assets_historical_returns.columns)
    results.append(first_results.mean().values)
average_results_all_coins_out_of_sample_rolling = pd.DataFrame(results, index=stop_loss_factors, columns=first_results.columns)
average_results_all_coins_out_of_sample_rolling

4.2. Results for ethereum¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01

coin_results_out_of_sample_rolling = pd.DataFrame()
rets = pd.DataFrame()
coin = 'ethereum'
for stop_loss_factor in stop_loss_factors:
    predicted_returns = conn2.sql_to_df(f'select * from RF_3Factor where asset = \'{coin}\' and window = {window} order by date')
    predicted_returns['Date'] = pd.to_datetime(predicted_returns.Date)
    predicted_returns.set_index(['Date'], inplace=True)
    predicted_returns = predicted_returns.predicted_return
    ground_truth = (assets_historical_returns.loc[predicted_returns.index, coin]>=0).astype(int).replace(0,-1)
    predictions = (predicted_returns>=0).astype(int).replace(0,-1)
    signals = predictions - ground_truth
    win_rate = (signals==0).sum()/len(signals)

    strategy_returns = (assets_historical_returns.loc[predicted_returns.index,coin] * predictions).fillna(0)
    strategy_returns.loc[strategy_returns>=0] = strategy_returns.loc[strategy_returns>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
    strategy_returns.loc[strategy_returns<0] = strategy_returns.loc[strategy_returns<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

    # Perform the one-sample t-test
    t_test = stats.ttest_1samp(a=strategy_returns, popmean=0, alternative='greater')
    
    t_stat = t_test.statistic
    p_value = t_test.pvalue
    avg_daily_rets = strategy_returns.mean()
    
    first_results = pd.DataFrame({'win_rate':win_rate, 't_stats':t_stat, 'p_value':p_value, 'avg_daily_return':avg_daily_rets}, index=[stop_loss_factor])
    
    coin_results_out_of_sample_rolling = pd.concat([coin_results_out_of_sample_rolling, first_results])
    rets = pd.concat([rets, strategy_returns.to_frame()], axis=1)
rets.columns = stop_loss_factors
coin_results_out_of_sample_rolling
In [ ]:
strategy_compounded_returns = rets.cumsum().apply(np.exp)
btc_bh = assets_historical_returns.loc[predicted_returns.index].bitcoin.cumsum().apply(np.exp)
btc_bh = btc_bh.append(pd.Series([1], index=[rets.index.min()-timedelta(days=1)])).sort_index()
btc_bh.name = 'Bitcoin'
portfolios_compared = pd.concat([strategy_compounded_returns,btc_bh], axis=1).fillna(1)
portfolios_compared.plot(figsize=(20,12), legend=True, logy=True)

5. Out-Of-Sample analysis (rolling - all windows)¶

5.1. Average results for all coins¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01

average_results_all_coins_out_of_sample_rolling_all_windows_concatinated = pd.DataFrame()
for window in np.linspace(30,16*30,16).astype(int):
    results=[]
    for stop_loss_factor in stop_loss_factors:
        t_stats = []
        p_values = []
        win_rates = []
        avg_daily_rets = []
        for coin in assets_historical_returns_out_of_sample.columns:
            predicted_returns = conn2.sql_to_df(f'select * from RF_3Factor where asset = \'{coin}\' and window = {window} order by date')
            predicted_returns['Date'] = pd.to_datetime(predicted_returns.Date)
            predicted_returns.set_index(['Date'], inplace=True)
            predicted_returns = predicted_returns.predicted_return
            ground_truth = (assets_historical_returns.loc[predicted_returns.index, coin]>=0).astype(int).replace(0,-1)
            predictions = (predicted_returns>=0).astype(int).replace(0,-1)
            signals = predictions - ground_truth
            win_rate = (signals==0).sum()/len(signals)

            strategy_returns_coin = (assets_historical_returns.loc[predicted_returns.index,coin] * predictions).fillna(0)
            strategy_returns_coin.loc[strategy_returns_coin>=0] = strategy_returns_coin.loc[strategy_returns_coin>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
            strategy_returns_coin.loc[strategy_returns_coin<0] = strategy_returns_coin.loc[strategy_returns_coin<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

            # Perform the one-sample t-test
            t_test = stats.ttest_1samp(a=strategy_returns_coin, popmean=0, alternative='greater')

            win_rates.append(win_rate)
            t_stats.append(t_test.statistic)
            p_values.append(t_test.pvalue)
            avg_daily_rets.append(strategy_returns_coin.mean())

        first_results = pd.DataFrame({'win_rate':win_rates, 't_stats':t_stats, 'p_value':p_values, 'avg_daily_returns':avg_daily_rets}, index=assets_historical_returns.columns)
        results.append(first_results.mean().values)
    average_results_all_coins_out_of_sample_rolling_all_windows = pd.DataFrame(results, index=stop_loss_factors, columns=first_results.columns)
    average_results_all_coins_out_of_sample_rolling_all_windows = average_results_all_coins_out_of_sample_rolling_all_windows.transpose()
    average_results_all_coins_out_of_sample_rolling_all_windows['window'] = window
    average_results_all_coins_out_of_sample_rolling_all_windows_concatinated = pd.concat([average_results_all_coins_out_of_sample_rolling_all_windows_concatinated,
                                                                                          average_results_all_coins_out_of_sample_rolling_all_windows
                                                                                         ])
    print(f'Window {window} is finished!')
average_results_all_coins_out_of_sample_rolling_all_windows_concatinated
In [ ]:
average_results_all_coins_out_of_sample_rolling_all_windows_concatinated.to_excel('average_results_all_coins_out_of_sample_rolling_all_windows.xlsx')

5.2. Results for ethereum¶

In [ ]:
stop_loss_factors = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
winnings_discount = 0.5 ## percentage of the stop loss factor that is applied to the winiing trades
trading_fees_factor = 0.01

coin_results_out_of_sample_rolling_all_windows_concatinated = pd.DataFrame()
rets_concatinated = pd.DataFrame()
for window in np.linspace(30,16*30,16).astype(int):
    coin_results_out_of_sample_rolling_all_windows = pd.DataFrame()
    rets = pd.DataFrame()
    coin = 'ethereum'
    for stop_loss_factor in stop_loss_factors:
        predicted_returns = conn2.sql_to_df(f'select * from RF_3Factor where asset = \'{coin}\' and window = {window} order by date')
        predicted_returns['Date'] = pd.to_datetime(predicted_returns.Date)
        predicted_returns.set_index(['Date'], inplace=True)
        predicted_returns = predicted_returns.predicted_return
        ground_truth = (assets_historical_returns.loc[predicted_returns.index, coin]>=0).astype(int).replace(0,-1)
        predictions = (predicted_returns>=0).astype(int).replace(0,-1)
        signals = predictions - ground_truth
        win_rate = (signals==0).sum()/len(signals)

        strategy_returns = (assets_historical_returns.loc[predicted_returns.index,coin] * predictions).fillna(0)
        strategy_returns.loc[strategy_returns>=0] = strategy_returns.loc[strategy_returns>=0]*(1-(stop_loss_factor*winnings_discount))*(1-trading_fees_factor)
        strategy_returns.loc[strategy_returns<0] = strategy_returns.loc[strategy_returns<0]*(1-stop_loss_factor)*(1+trading_fees_factor)

        # Perform the one-sample t-test
        t_test = stats.ttest_1samp(a=strategy_returns, popmean=0, alternative='greater')

        t_stat = t_test.statistic
        p_value = t_test.pvalue
        avg_daily_rets = strategy_returns.mean()

        first_results = pd.DataFrame({'win_rate':win_rate, 't_stats':t_stat, 'p_value':p_value, 'avg_daily_return':avg_daily_rets}, index=[stop_loss_factor])

        coin_results_out_of_sample_rolling_all_windows = pd.concat([coin_results_out_of_sample_rolling_all_windows, first_results])
        rets = pd.concat([rets, strategy_returns.to_frame()], axis=1)
    rets.columns = stop_loss_factors
    rets['window'] = window
    rets_concatinated = pd.concat([rets_concatinated, rets])
    coin_results_out_of_sample_rolling_all_windows
    coin_results_out_of_sample_rolling_all_windows = coin_results_out_of_sample_rolling_all_windows.transpose()
    coin_results_out_of_sample_rolling_all_windows['window'] = window
    coin_results_out_of_sample_rolling_all_windows_concatinated = pd.concat([coin_results_out_of_sample_rolling_all_windows_concatinated,
                                                                             coin_results_out_of_sample_rolling_all_windows
                                                                            ])
    print(f'Window {window} is finished!')
coin_results_out_of_sample_rolling_all_windows_concatinated
In [ ]:
coin_results_out_of_sample_rolling_all_windows_concatinated.to_excel('coin_results_out_of_sample_rolling_all_windows.xlsx')
In [ ]:
# rets_concatinated.drop(['2022-01-10'], inplace=True)
rets_to_plot0 = rets_concatinated.reset_index().pivot(index='Date', columns='window', values=0.0).dropna()
rets_to_plot1 = rets_concatinated.reset_index().pivot(index='Date', columns='window', values=0.1).dropna()
rets_to_plot2 = rets_concatinated.reset_index().pivot(index='Date', columns='window', values=0.2).dropna()
rets_to_plot3 = rets_concatinated.reset_index().pivot(index='Date', columns='window', values=0.3).dropna()
rets_to_plot4 = rets_concatinated.reset_index().pivot(index='Date', columns='window', values=0.4).dropna()
rets_to_plot5 = rets_concatinated.reset_index().pivot(index='Date', columns='window', values=0.5).dropna()

strategy_compounded_returns0 = rets_to_plot0.cumsum().apply(np.exp)
strategy_compounded_returns1 = rets_to_plot1.cumsum().apply(np.exp)
strategy_compounded_returns2 = rets_to_plot2.cumsum().apply(np.exp)
strategy_compounded_returns3 = rets_to_plot3.cumsum().apply(np.exp)
strategy_compounded_returns4 = rets_to_plot4.cumsum().apply(np.exp)
strategy_compounded_returns5 = rets_to_plot5.cumsum().apply(np.exp)

btc_bh = assets_historical_returns.loc[predicted_returns.index].bitcoin.cumsum().apply(np.exp)
btc_bh = btc_bh.append(pd.Series([1], index=[rets.index.min()-timedelta(days=1)])).sort_index()
btc_bh.name = 'Bitcoin'

portfolios_compared0 = pd.concat([strategy_compounded_returns0,btc_bh], axis=1).ffill()
portfolios_compared1 = pd.concat([strategy_compounded_returns1,btc_bh], axis=1).ffill()
portfolios_compared2 = pd.concat([strategy_compounded_returns2,btc_bh], axis=1).ffill()
portfolios_compared3 = pd.concat([strategy_compounded_returns3,btc_bh], axis=1).ffill()
portfolios_compared4 = pd.concat([strategy_compounded_returns4,btc_bh], axis=1).ffill()
portfolios_compared5 = pd.concat([strategy_compounded_returns5,btc_bh], axis=1).ffill()
In [ ]:
plt.subplots(3, 2, figsize=(30,20))

ax1 = plt.subplot(3, 2, 1)
portfolios_compared0.plot(ax=ax1, legend=False, logy=True, title='Risk Mitigation Factor = 0.0')
ax2 = plt.subplot(3, 2, 2)
portfolios_compared1.plot(ax=ax2, legend=False, logy=True, title='Risk Mitigation Factor = 0.1')
ax3 = plt.subplot(3, 2, 3)
portfolios_compared2.plot(ax=ax3, legend=False, logy=True, title='Risk Mitigation Factor = 0.2')
ax4 = plt.subplot(3, 2, 4)
portfolios_compared3.plot(ax=ax4, legend=False, logy=True, title='Risk Mitigation Factor = 0.3')
ax5 = plt.subplot(3, 2, 5)
portfolios_compared4.plot(ax=ax5, legend=False, logy=True, title='Risk Mitigation Factor = 0.4')
ax6 = plt.subplot(3, 2, 6)
portfolios_compared5.plot(ax=ax6, legend=False, logy=True, title='Risk Mitigation Factor = 0.5')

for i, lines in enumerate(zip(ax1.lines, ax2.lines, ax3.lines, ax4.lines, ax5.lines, ax6.lines)):
    if i == 16:
        for line in lines:
            line.set_color('black')
            line.set_marker('*')

plt.show()

6. Comparing results of Fama-Macbeth model¶

6.1. Across all coins¶

6.1.1. In-sample¶

In [ ]:
average_results_all_coins_in_sample

6.1.2. Out-of-sample (static)¶

In [ ]:
average_results_all_coins_out_of_sample

6.1.3. Out-of-sample (rolling - 1Y window)¶

In [ ]:
average_results_all_coins_out_of_sample_rolling

6.1.4. Out-of-sample (rolling - all windows)¶

In [ ]:
average_results_all_coins_out_of_sample_rolling_all_windows_concatinated

6.2. for Ethereum¶

6.2.1. In-sample¶

In [ ]:
coin_results_in_sample

6.2.2. Out-of-sample (static)¶

In [ ]:
coin_results_out_of_sample

6.2.3. Out-of-sample (rolling - 1Y window)¶

In [ ]:
coin_results_out_of_sample_rolling

6.2.4. Out-of-sample (rolling - all windows)¶

In [ ]:
coin_results_out_of_sample_rolling_all_windows_concatinated
In [ ]: